package com.quanshu.exchange.support.chat;

import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;

import com.hyphenate.EMCallBack;
import com.hyphenate.EMConnectionListener;
import com.hyphenate.EMContactListener;
import com.hyphenate.EMError;
import com.hyphenate.EMGroupChangeListener;
import com.hyphenate.EMMessageListener;
import com.hyphenate.chat.EMClient;
import com.hyphenate.chat.EMMessage;
import com.hyphenate.chat.EMMucSharedFile;
import com.hyphenate.chat.EMOptions;
import com.quanshu.exchange.support.api.UserInterface;
import com.quanshu.exchange.support.config.Config;
import com.quanshu.exchange.support.db.GroupDao;
import com.quanshu.exchange.support.db.UserDao;
import com.quanshu.exchange.support.entity.GroupEntity;
import com.quanshu.exchange.support.entity.UserEntity;
import com.quanshu.exchange.support.helper.NotificationHelper;
import com.quanshu.exchange.support.net.BaseResponse;
import com.quanshu.exchange.support.net.core.BaseObserver;
import com.quanshu.exchange.support.net.core.NetClient;
import com.quanshu.exchange.support.utils.AppUtils;
import com.quanshu.exchange.support.utils.LogUtil;
import com.quanshu.exchange.ui.base.MyApplication;
import com.quanshu.exchange.ui.gui.HomePageActivity;
import com.quanshu.exchange.ui.gui.message.chat.CallReceiver;

import java.util.List;

import static com.quanshu.exchange.support.helper.NotificationHelper.TYPE_ADD_AS_FRIEND;
import static com.quanshu.exchange.support.helper.NotificationHelper.TYPE_RECEIVE_GROUP_APPLY;

/**
 * Created by jye on 2017/11/23.
 */
public class ChatHelper {

    private Context context;

    private volatile boolean isEMContactListenerAdded = false;
    private volatile boolean isEMGroupListenerAdded = false;

    private NotificationHelper notificationHelper;
    private LocalBroadcastManager broadcastManager;
    private CallReceiver callReceiver;

    private volatile static ChatHelper instance;

    public static ChatHelper getInstance() {
        if (instance == null) {
            synchronized (ChatHelper.class) {
                if (instance == null) {
                    instance = new ChatHelper();
                }
            }
        }
        return instance;
    }

    private ChatHelper() {
    }

    /**
     * 初始化
     *
     * @param context
     */
    public void init(Context context) {
        this.context = context;
        int pid = android.os.Process.myPid();
        String processAppName = AppUtils.getProcessName(context, pid);
        // 如果APP启用了远程的service，此application:onCreate会被调用2次
        // 为了防止环信SDK被初始化2次，加此判断会保证SDK被初始化1次
        // 默认的APP会在以包名为默认的process name下运行，如果查到的process name不是APP的process name就立即返回
        if (processAppName == null || !processAppName.equalsIgnoreCase(context.getPackageName())) {
            // 则此application::onCreate 是被service 调用的，直接返回
            return;
        }
        initChatOption();
        setEMConnectionListener();
        addEMContactListener();
        addGroupChangeListener();
        addMessageListener();
        initCallReceive();
        notificationHelper = NotificationHelper.getInstance();
        broadcastManager = LocalBroadcastManager.getInstance(context);
    }

    private void addMessageListener() {
        EMMessageListener messageListener = new EMMessageListener() {
            @Override
            public void onMessageReceived(List<EMMessage> messages) {
                EMMessage emMessage = messages.get(messages.size() - 1);
                String destId = MyApplication.getInstance().getCurrentChatUsername();
                if (EMMessage.ChatType.Chat.equals(emMessage.getChatType()) && !destId.equals(emMessage.getFrom())) {
                    NotificationHelper.getInstance().showNotification(NotificationHelper.getMessageNotifyType(emMessage), emMessage);
                }
                if (EMMessage.ChatType.GroupChat.equals(emMessage.getChatType()) && !destId.equals(emMessage.getTo())) {
                    NotificationHelper.getInstance().showNotification(NotificationHelper.getMessageNotifyType(emMessage), emMessage);
                }
            }

            @Override
            public void onCmdMessageReceived(List<EMMessage> messages) {
            }

            @Override
            public void onMessageRead(List<EMMessage> messages) {
            }

            @Override
            public void onMessageDelivered(List<EMMessage> messages) {
            }

            @Override
            public void onMessageRecalled(List<EMMessage> messages) {
            }

            @Override
            public void onMessageChanged(EMMessage message, Object change) {
            }
        };
        EMClient.getInstance().chatManager().addMessageListener(messageListener);
    }

    private void initChatOption() {
        EMOptions options = new EMOptions();
        options.setAcceptInvitationAlways(false);
        options.setRequireAck(true);
        options.setRequireDeliveryAck(false);
        // TODO
        // options.setMipushConfig("2882303761517426801", "5381742660801");
        // options.setHuaweiPushAppId("10740968");
        EMClient.getInstance().init(context, options);
    }

    /**
     * 环信连接回调
     */
    private void setEMConnectionListener() {
        EMConnectionListener connectionListener = new EMConnectionListener() {
            @Override
            public void onDisconnected(int error) {
                LogUtil.print("===EMConnectionListener==onDisconnected==error=" + error);
                if (error == EMError.USER_REMOVED) {
                    onUserException(ChatConstant.ACCOUNT_REMOVED);
                } else if (error == EMError.USER_LOGIN_ANOTHER_DEVICE) {
                    onUserException(ChatConstant.ACCOUNT_CONFLICT);
                } else if (error == EMError.SERVER_SERVICE_RESTRICTED) {
                    onUserException(ChatConstant.ACCOUNT_FORBIDDEN);
                } else if (error == EMError.USER_KICKED_BY_CHANGE_PASSWORD) {
                    onUserException(ChatConstant.ACCOUNT_KICKED_BY_CHANGE_PASSWORD);
                } else if (error == EMError.USER_KICKED_BY_OTHER_DEVICE) {
                    onUserException(ChatConstant.ACCOUNT_KICKED_BY_OTHER_DEVICE);
                }
            }

            @Override
            public void onConnected() {
                LogUtil.print("===EMConnectionListener==onConnected===");
            }
        };
        EMClient.getInstance().addConnectionListener(connectionListener);
    }

    /**
     * user met some exception: conflict, removed or forbidden
     */
    protected void onUserException(String exception) {
        Intent intent = new Intent(context, HomePageActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra(exception, true);
        context.startActivity(intent);
    }

    private void initCallReceive() {
        IntentFilter callFilter = new IntentFilter(EMClient.getInstance().callManager().getIncomingCallBroadcastAction());
        if (callReceiver == null) {
            callReceiver = new CallReceiver();
        }
        //register incoming call receiver
        context.registerReceiver(callReceiver, callFilter);
    }

    /**
     * 环信好友回调
     */
    private void addEMContactListener() {
        if (!isEMContactListenerAdded) {
            EMContactListener contactListener = new EMContactListener() {
                @Override
                public void onContactAdded(String username) {
                    LogUtil.print("==onContactAdded==" + username);
                    onContactAdd(username);
                    MyApplication.getInstance().removeHasBeenDelFriend(username);
                }

                @Override
                public void onContactDeleted(String username) {
                    LogUtil.print("==onContactDeleted==" + username);
                    UserDao.getInstance().delete(username);
                    EMClient.getInstance().chatManager().deleteConversation(username, true);
                    MyApplication.getInstance().addHasBeenDelFriend(username);
                }

                @Override
                public void onContactInvited(String username, String reason) {
                    LogUtil.print("==onContactInvited=username=" + username + "====reason=" + reason);
                    onContactInvite(username, reason);
                }

                @Override
                public void onFriendRequestAccepted(String username) {
                    LogUtil.print("==onFriendRequestAccepted==" + username);

                }

                @Override
                public void onFriendRequestDeclined(String username) {
                    LogUtil.print("==onFriendRequestDeclined==" + username);
                }
            };
            EMClient.getInstance().contactManager().setContactListener(contactListener);
            isEMContactListenerAdded = true;
        }
    }

    /**
     * 群变化回调listener
     */
    private void addGroupChangeListener() {
        if (!isEMGroupListenerAdded) {
            EMClient.getInstance().groupManager().addGroupChangeListener(new GroupChangeListener());
            isEMGroupListenerAdded = true;
        }
    }

    class GroupChangeListener implements EMGroupChangeListener {

        //当前用户收到加入群组邀请
        @Override
        public void onInvitationReceived(String groupId, String groupName, String inviter, String reason) {
            LogUtil.print("==onInvitationReceived==" + groupId);
        }

        //用户申请加入群
        @Override
        public void onRequestToJoinReceived(String groupId, String groupName, String applicant, String reason) {
            LogUtil.print("==onRequestToJoinReceived==" + groupId);
            doOnRequestToJoinReceived(groupId, groupName, applicant, reason);

        }

        //加群申请被同意
        @Override
        public void onRequestToJoinAccepted(String groupId, String groupName, String accepter) {
            LogUtil.print("==onRequestToJoinAccepted==" + groupId);
        }

        //加群申请被拒绝
        @Override
        public void onRequestToJoinDeclined(String groupId, String groupName, String decliner, String reason) {
            LogUtil.print("==onRequestToJoinDeclined==" + groupId);
        }

        //群组邀请被同意
        @Override
        public void onInvitationAccepted(String groupId, String invitee, String reason) {
            LogUtil.print("==onInvitationAccepted==" + groupId);
        }

        //群组邀请被拒绝
        @Override
        public void onInvitationDeclined(String groupId, String invitee, String reason) {
            LogUtil.print("==onInvitationDeclined==" + groupId);
        }

        //当前登录用户被管理员移除出群组
        @Override
        public void onUserRemoved(String groupId, String groupName) {
            LogUtil.print("==onUserRemoved==" + groupId);
            GroupDao.getInstance().delete(groupId);
        }

        //群组被解散。
        @Override
        public void onGroupDestroyed(String groupId, String groupName) {
            LogUtil.print("==onGroupDestroyed==" + groupId);
        }

        // 自动同意加入群组
        @Override
        public void onAutoAcceptInvitationFromGroup(String groupId, String inviter, String inviteMessage) {
            LogUtil.print("==onAutoAcceptInvitationFromGroup==" + groupId);
        }

        //成员禁言的通知
        @Override
        public void onMuteListAdded(String groupId, List<String> mutes, long muteExpire) {
            LogUtil.print("==onMuteListAdded==" + groupId);
        }

        //成员从禁言列表里移除通知
        @Override
        public void onMuteListRemoved(String groupId, List<String> mutes) {
            LogUtil.print("==onMuteListRemoved==" + groupId);
        }

        //增加管理员的通知
        @Override
        public void onAdminAdded(String groupId, String administrator) {
            LogUtil.print("==onAdminAdded==" + groupId);
        }

        //管理员移除的通知
        @Override
        public void onAdminRemoved(String groupId, String administrator) {
            LogUtil.print("==onAdminRemoved==" + groupId);
        }

        //群所有者变动通知
        @Override
        public void onOwnerChanged(String groupId, String newOwner, String oldOwner) {
            LogUtil.print("==onOwnerChanged==" + groupId);
            GroupEntity groupEntity = GroupDao.getInstance().query(groupId);
            if (groupEntity != null) {
                groupEntity.setOwner(newOwner);
                GroupDao.getInstance().save(groupEntity);
            }
        }

        @Override
        public void onMemberJoined(String groupId, String member) {

        }

        @Override
        public void onMemberExited(String groupId, String member) {

        }

        @Override
        public void onAnnouncementChanged(String groupId, String announcement) {

        }

        @Override
        public void onSharedFileAdded(String groupId, EMMucSharedFile sharedFile) {

        }

        @Override
        public void onSharedFileDeleted(String groupId, String fileId) {

        }
    }

    synchronized void reset() {
        isEMContactListenerAdded = false;
        isEMGroupListenerAdded = false;
    }

    private void onContactInvite(String username, String reason) {
        NetClient.getInstance()
                .getNetService(UserInterface.class)
                .getUser(AppUtils.getSignParams(username), username)
                .subscribe(new BaseObserver<BaseResponse<UserEntity>>() {
                    @Override
                    public void onSuccess(BaseResponse<UserEntity> response) {
                        UserEntity userEntity = response.getInfo();
                        notificationHelper.showNotification(TYPE_ADD_AS_FRIEND, userEntity.getMemberid());
                        broadcastManager.sendBroadcast(new Intent(Config.ACTION_NOTIFY_CHANGED));
                    }
                });
    }

    private void onContactAdd(String username) {
        NetClient.getInstance()
                .getNetService(UserInterface.class)
                .getUser(AppUtils.getSignParams(username), username)
                .subscribe(new BaseObserver<BaseResponse<UserEntity>>() {
                    @Override
                    public void onSuccess(BaseResponse<UserEntity> response) {
                        UserEntity userEntity = response.getInfo();
                        UserDao.getInstance().save(userEntity);
                    }
                });
    }

    /**
     * //接收到群组加入邀请
     *
     * @param groupId
     * @param groupName
     * @param applicant
     * @param reason
     */
    private void doOnRequestToJoinReceived(String groupId, String groupName, String applicant, String reason) {
        GroupEntity groupEntity = GroupDao.getInstance().query(groupId);
        if (groupEntity != null) {
            notificationHelper.showNotification(TYPE_RECEIVE_GROUP_APPLY, groupEntity, applicant, reason);
            broadcastManager.sendBroadcast(new Intent(Config.ACTION_NOTIFY_CHANGED));
        }
    }

    /**
     * logout
     *
     * @param unbindDeviceToken whether you need unbind your device token
     * @param callback          callback
     */
    public void logout(boolean unbindDeviceToken, final EMCallBack callback) {
        endCall();
        EMClient.getInstance().logout(unbindDeviceToken, new EMCallBack() {
            @Override
            public void onSuccess() {
                reset();
                if (callback != null) {
                    callback.onSuccess();
                }
            }

            @Override
            public void onProgress(int progress, String status) {
                if (callback != null) {
                    callback.onProgress(progress, status);
                }
            }

            @Override
            public void onError(int code, String error) {
                reset();
                if (callback != null) {
                    callback.onError(code, error);
                }
            }
        });
    }

    void endCall() {
        try {
            EMClient.getInstance().callManager().endCall();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
